#include "precompiled.h"
#include "character.h"
using namespace std;
using namespace weo::engine;
using namespace weo::engine::item;
using namespace weo::engine::character;
std::set<unsigned int> Character::s_Whitelist;
std::set<unsigned int> Character::s_Blacklist;
Equipment& Equipment::operator=(const Equipment& equip)
{
    if(this != &equip)
    {
        setEquip(equip.Items,equip.Gems,equip.Enchants);
        Fitness = equip.Fitness;
    }
    return *this;
}
bool Equipment::saveEquipmentToFile(std::string classname, std::string buildname,std::string filename)
{
    if(filename.empty()) return false;
    ticpp::Document doc;  
    ticpp::Element* msg;
    ticpp::Element* msgs;
    ticpp::Declaration* decl;
    ticpp::Element* root;
    ticpp::Comment* comment;
    ticpp::Element* info;
    try
    {
        decl = new (UseGC) ticpp::Declaration( "1.0", "", "" );  
        doc.LinkEndChild( decl );  
        root = new ticpp::Element( "equipmentprofile" );  
        doc.LinkEndChild( root );  
        comment = new (UseGC) ticpp::Comment();
        comment->SetValue(" Equipment Profile for WOW Equip Optimizer 2.0 " );  
        root->LinkEndChild( comment ); 
        info = new (UseGC) ticpp::Element( "information" );  
        root->LinkEndChild( info ); 
        msg = new (UseGC) ticpp::Element( "class",classname);  
        info->LinkEndChild( msg );
        msg = new (UseGC) ticpp::Element( "build",buildname);  
        info->LinkEndChild( msg );
        msgs = new (UseGC) ticpp::Element( "items" );  
        root->LinkEndChild( msgs ); 
        for(int i = 0;i<weo::engine::Slotcount;i++)
        {
            msg = new (UseGC) ticpp::Element( "item", Items[i] == 0 ? "0" : Items[i]->Id() == Item::None()->Id() ? "0" : boost::lexical_cast<std::string>(Items[i]->Id()));  
            msgs->LinkEndChild( msg ); 
        }
        msgs = new (UseGC) ticpp::Element( "gems" );  
        root->LinkEndChild( msgs ); 
        for(int i = 0;i<weo::engine::Slotcount*3;i++)
        {
            msg = new (UseGC) ticpp::Element( "gem", Gems[i] == 0 ? "0" : boost::lexical_cast<std::string>(Gems[i]->Id()));  
            msgs->LinkEndChild( msg );
        }
        msgs = new (UseGC) ticpp::Element( "enchants" );  
        root->LinkEndChild( msgs ); 
        for(int i = 0;i<weo::engine::Slotcount;i++)
        {
            msg = new (UseGC) ticpp::Element( "enchant",Enchants[i] == 0 ? "0" : boost::lexical_cast<std::string>(Enchants[i]->Id()) );  
            msgs->LinkEndChild( msg ); 
        }
        doc.SaveFile(filename);
    }
    catch( ticpp::Exception& ex )
    {
        return false;
    }
    return true;
}
void Equipment::filterEquip(const std::vector<std::vector<const weo::engine::item::Item*>> m_Items)
{
    for(int i = 0;i<weo::engine::Slotcount;i++)
    {
        std::vector<const weo::engine::item::Item*> items = m_Items[i];
        std::vector<const weo::engine::item::Item*>::const_iterator it;
        bool found = false;
        const Item *item = Items[i];
        if(item == NULL)
        {
            continue;
        }
        for(it = items.begin(); it != items.end(); it++)
        {
            if(item->Id() == (*it)->Id())
            {
                found = true;
                break;
            }
        }
        if(!found)
        {
            Items[i] = Item::None();
            memset(Gems,0,sizeof(GemPtr)*3);
        }
    }
}
std::pair<std::string,std::string> Equipment::loadEquipmentFromFile(std::string filename)
{
    std::pair<std::string,std::string> retval("","");
    if(filename.empty()) return retval;
    for(int i = 0;i<weo::engine::Slotcount;i++)
    {
        Items[i] = Item::None();
    }
    memset(Gems,0,sizeof(GemPtr)*weo::engine::Slotcount*3);
    memset(Enchants,0,sizeof(EnchantPtr)*weo::engine::Slotcount);
    try
    {
        ticpp::Document doc( "Equipment Profile" );
        doc.LoadFile(filename);
        ticpp::Element *pParent = doc.FirstChildElement("equipmentprofile",true);
        if(pParent != NULL)
        {
            ticpp::Element *pElem = pParent->FirstChildElement("information", true);
            if(pElem != NULL)
            {
                ticpp::Element *pChild = pElem->FirstChildElement("class",false);
                if(pChild != NULL)
                {
                    retval.first = pChild->GetText(false);
                }
                pChild = pElem->FirstChildElement("build",false);
                if(pChild != NULL)
                {
                    retval.second = pChild->GetText(false);
                }
            }
            pElem = pParent->FirstChildElement("items", true);
            if(pElem != NULL)
            {
                ticpp::Element *pChild = pElem->FirstChildElement("item",false);
                int counter = 0;
                while(pChild != NULL)
                {
                    int itemid = boost::lexical_cast<int>(pChild->GetText(false));
                    if(itemid != 0) Items[counter] = Itemdatabase::getInstance()->getPtrbyId(itemid);
                    pChild = pChild->NextSiblingElement("item",false);
                    counter++;
                }
            }
            pElem = pParent->FirstChildElement("gems", true);
            if(pElem != NULL)
            {
                ticpp::Element *pChild = pElem->FirstChildElement("gem",false);
                int counter = 0;
                while(pChild != NULL)
                {
                    int gemid = boost::lexical_cast<int>(pChild->GetText(false));
                    if(gemid != 0) Gems[counter] = Itemdatabase::getInstance()->getPtrbyId(gemid);
                    pChild = pChild->NextSiblingElement("gem",false);
                    counter++;
                }
            }
            pElem = pParent->FirstChildElement("enchants", true);
            if(pElem != NULL)
            {
                ticpp::Element *pChild = pElem->FirstChildElement("enchant",false);
                int counter = 0;
                while(pChild != NULL)
                {
                    int enchantid = boost::lexical_cast<int>(pChild->GetText(false));
                    if(enchantid != 0) Enchants[counter] = Enchant::GetEnchantById(enchantid);
                    pChild = pChild->NextSiblingElement("enchant",false);
                    counter++;
                }
            }
        }
    }
    catch( ticpp::Exception& ex )
    {
        return retval;
    }
    return retval;
}
std::pair<std::string,std::string> Equipment::getEquipmentFromWeb(std::string url)
{
    std::pair<std::string,std::string> retval("","");
    if(url.empty()) return retval;
    boost::to_lower(url);
    boost::trim(url);
    boost::replace_first(url,"http://","");
    std::string::size_type pos = url.find("/");
    if(pos == std::string::npos)
    {
        return retval;
    }
    std::string host = url.substr(0,pos);
    std::string file = url.substr(pos,url.size());
    weo::engine::utility::HttpGet *hget = new weo::engine::utility::HttpGet(host,file,"text/xml");
    if(hget->Data().find("</page>") == string::npos)
    {
        return retval; // if there is  no </page> the page wasn't loaded properly
    }
    int build[3];
    if(hget->Error()) return retval;
    int slotconversion[] = { 0, 1, 2, -1, 4, 7, 8, 9, 5, 6, 10, 11, 12, 13, 3, 14, 15, 16, -1 };
    try
    {
        ticpp::Document doc( "Equipment Profile" );
        doc.Parse(hget->Data(),false,TIXML_ENCODING_UNKNOWN);
        ticpp::Element *pParent = doc.FirstChildElement()->FirstChildElement("characterInfo",true);
        if(pParent != NULL)
        {
            ticpp::Element *pElem = pParent->FirstChildElement("character", true);
            if(pElem != NULL)
            {
                ticpp::Attribute* pName = pElem->FirstAttribute(true)->Next(true)->Next(true);
                if(pName != NULL)
                {
                    retval.first = pName->Value();
                }
            }
            pElem = pParent->FirstChildElement("characterTab",true)->FirstChildElement("talentSpec",true);
            if(pElem != NULL)
            {
                ticpp::Attribute* pName = pElem->FirstAttribute(true);
                build[0] = boost::lexical_cast<int>(pName->Value());
                pName = pName->Next();
                build[2] = boost::lexical_cast<int>(pName->Value());
                pName = pName->Next();
                build[1] = boost::lexical_cast<int>(pName->Value());
            }
            pElem = pParent->FirstChildElement("characterTab",true)->FirstChildElement("items",true);
            if(pElem != NULL)
            {
                ticpp::Element *pChild = pElem->FirstChildElement("item",false);
                int gemids[3];
                int itemid;
                int slotid = 0;
                int enchantid;
                for(int i = 0;i<weo::engine::Slotcount;i++)
                {
                    Items[i] = Item::None();
                }
                memset(Gems,0,sizeof(GemPtr)*weo::engine::Slotcount*3);
                memset(Enchants,0,sizeof(EnchantPtr)*weo::engine::Slotcount);
                while(pChild != NULL)
                {
                    ticpp::Attribute* pName = pChild->FirstAttribute(true);
                    for(int i = 0;i<3;i++)
                    {
                        pName = pName->Next();
                        gemids[i] = boost::lexical_cast<int>(pName->Value());
                    }
                    pName = pName->Next()->Next();
                    itemid = boost::lexical_cast<int>(pName->Value());
                    pName = pName->Next()->Next();
                    enchantid = boost::lexical_cast<int>(pName->Value());
                    pName = pName->Next()->Next()->Next();
                    slotid = boost::lexical_cast<int>(pName->Value());
                    if(slotid >= 0)
                    {
                        int counter = slotconversion[slotid];
                        if(counter != -1)
                        {
                            Items[counter] = Itemdatabase::getInstance()->getPtrbyId(itemid);
                            for(int i = 0;i<3;i++)
                            {
                                if(gemids[i] > 0)
                                {
                                    Gems[counter*3+i] = Itemdatabase::getInstance()->getPtrbyId(gemids[i]);
                                }
                            }
                            Enchants[counter] = Enchant::GetEnchantById(enchantid);
                        }
                    }
                    pChild = pChild->NextSiblingElement("item",false);
                }
            }
        }
    }
    catch( ticpp::Exception& ex )
    {
        retval.first = "";
        return retval;
    }
    std::vector<std::string> builds = CharacterFactory::GetBuilds(retval.first);
    for(unsigned int i = 0;i<builds.size();i++)
    {
        Character *testchar = CharacterFactory::CallFactory<Character>(retval.first,builds[i]);
        if(testchar->evaluateBuild(build[0],build[1],build[2]))
        {
            retval.second = builds[i];
            break;
        }
    }
    Fitness = 0;
    return retval;
}

void Character::Init()
{
    Equipcom::UseWeaponProcs(true);
    if(ClassMap.empty())
    {
        InitChar();
    }
    m_HasBok = Buff::Bok();
    m_Classnr = 511;
    m_AttributesStart = 0;
    m_AttributesStop = m_AttributesVector.size()-1;
    initBuffs();
    initGoodAttributes();
    m_FilterBelow = Itemdatabase::getInstance()->getMinLevel();
    m_FilterAbove = Itemdatabase::getInstance()->getMaxLevel();
    m_FilterSource = 0;
    m_FilterQuality = 3;
    const std::vector<std::string>* list = Itemdatabase::getInstance()->getAreaVector();
    for(unsigned int i = 0;i<list->size();i++)
    {
        m_FilterArea[list->at(i)] = false;
    }
}
void Character::initBuffs()
{
    Buff *ai = new Buff("Arcane Intellect");
    ai->addAttribute(Attribute("Intellect",40));
    Buff *pwf = new Buff("Power Word: Fortitude");
    pwf->addAttribute(Attribute("Stamina",79*1.3f));
    Buff *ds = new Buff("Divine Spirit");
    ds->addAttribute(Attribute("Spirit",50));
    Buff *gotw = new Buff("Gift of the Wild");
    gotw->addAttribute(Attribute("Armor", 340 * 1.35f));
    gotw->addAttribute(Attribute("Agility", 14 * 1.35f));
    gotw->addAttribute(Attribute("Intellect", 14 * 1.35f));
    gotw->addAttribute(Attribute("Stamina", 14 * 1.35f));
    gotw->addAttribute(Attribute("Strength", 14 * 1.35f));
    gotw->addAttribute(Attribute("Spirit", 14 * 1.35f));
    gotw->addAttribute(Attribute("ShadowResist", 25 * 1.35f));
    gotw->addAttribute(Attribute("FireResist", 25 * 1.35f));
    gotw->addAttribute(Attribute("FrostResist", 25 * 1.35f));
    gotw->addAttribute(Attribute("NatureResist", 25 * 1.35f));
    gotw->addAttribute(Attribute("ArcaneResist", 25 * 1.35f));
    Buff *spmp = new Buff("Shadow Priest MP5");
    spmp->addAttribute(Attribute("MP5",250));
    spmp->Active(false);
    Buff *sphp = new Buff("Shadow Priest HP5");
    sphp->addAttribute(Attribute("HP5",750));
    sphp->Active(false);
    m_Buffs[ai->Name()] = *ai;
    m_Buffs[pwf->Name()] = *pwf;
    m_Buffs[ds->Name()] = *ds;
    m_Buffs[gotw->Name()] = *gotw;
    m_Buffs[spmp->Name()] = *spmp;
    m_Buffs[sphp->Name()] = *sphp;

    // generic

    Buff *comshout = new Buff("Commanding Shout");
    comshout->addAttribute(Attribute("Health", 1080));
    comshout->Active(false);
    m_Buffs[comshout->Name()] = *comshout;

    Buff *crawdad = new Buff("Spicy Crawdad");
    crawdad->addAttribute(Attribute("Stamina", 30));
    crawdad->addAttribute(Attribute("Spirit", 20));
    crawdad->Active(false);
    m_Buffs[crawdad->Name()] = *crawdad;

    Buff *bloodpact = new Buff("Blood Pact");
    bloodpact->addAttribute(Attribute("Stamina", 70 * 1.3f));
    bloodpact->Active(false);
    m_Buffs[bloodpact->Name()] = *bloodpact;


    // caster/healer
    Buff *airwrath = new Buff("Wrath of Air Totem");
    airwrath->addAttribute(Attribute("SpellDamage", 103));
    airwrath->Active(false);
    m_Buffs[airwrath->Name()] = *airwrath;
    Buff *mstream = new Buff("Manastream Totem");
    mstream->addAttribute(Attribute("MP5", 20 * 1.25f * 2.5f));    
    mstream->Active(false);
    m_Buffs[mstream->Name()] = *mstream;
    Buff *bow = new Buff("Blessing of Wisdom");
    bow->addAttribute(Attribute("MP5", 41 * 1.2f));
    bow->Active(false);
    m_Buffs[bow->Name()] = *bow;
    Buff *manapotions = new Buff("Superior Mana Potions");
    manapotions->addAttribute(Attribute("MP5", 2400 / 24.0f));
    manapotions->Active(false);
    m_Buffs[manapotions->Name()] = *manapotions;
   
    Buff *tow = new Buff("Totem of Wrath");
    tow->addAttribute(Attribute("HitSpellRating",3.0f*HitSpellRating));
    tow->addAttribute(Attribute("CritSpellRating",3.0f*CritSpellRating));
    tow->Active(false);
    m_Buffs[tow->Name()] = *tow;

    Buff *mtide = new Buff("Manatide Totem");
    mtide->addAttribute(Attribute("MP5", 40));
    mtide->Active(false);
    m_Buffs[mtide->Name()] = *mtide;

    // melee

    Buff *bom = new Buff("Blessing of Might");
    bom->addAttribute(Attribute("AttackPower", 220));
    bom->Active(false); //
    m_Buffs[bom->Name()] = *bom;
    Buff *relassault = new Buff("Flask of Relentless Assault");
    relassault->addAttribute(Attribute("AttackPower", 120));
    relassault->Active(false); //
    m_Buffs[relassault->Name()] = *relassault;
    Buff *majagi = new Buff("Elixir of Major Agility");
    majagi->addAttribute(Attribute("Agility", 35));
    majagi->addAttribute(Attribute("CritRating", 20));
    majagi->Active(false);
    m_Buffs[majagi->Name()] = *majagi;
    Buff *battleshout = new Buff("Battleshout");
    battleshout->addAttribute(Attribute("AttackPower", 375));
    battleshout->Active(false);
    m_Buffs[battleshout->Name()] = *battleshout;
    Buff *lotp = new Buff("Leader of the pack");
    lotp->addAttribute(Attribute("CritRating", 5 * CritRating));
    lotp->Active(false); //
    m_Buffs[lotp->Name()] = *lotp;
    Buff *roastcleft = new Buff("Roasted Clefthoof");
    roastcleft->addAttribute(Attribute("Strength", 20));
    roastcleft->addAttribute(Attribute("Spirit", 20));
    roastcleft->Active(false); //
    m_Buffs[roastcleft->Name()] = *roastcleft;
    Buff *mudfish = new Buff("Grilled Mudfish");
    mudfish->addAttribute(Attribute("Agility", 20));
    mudfish->addAttribute(Attribute("Spirit", 20));
    mudfish->Active(false);
    m_Buffs[mudfish->Name()] = *mudfish;
    Buff *goa = new Buff("Grace of Air");
    goa->addAttribute(Attribute("Agility", 77 * 1.15f));
    goa->Active(false);
    m_Buffs[goa->Name()] = *goa;
    Buff *soe = new Buff("Strength of Earth");
    soe->addAttribute(Attribute("Strength", 88 * 1.15f));
    soe->Active(false); //
    m_Buffs[soe->Name()] = *soe;
    Buff *wftotem = new Buff("Windfury Totem");
    wftotem->addAttribute(Attribute("Special", 707723)); // wf totem
    wftotem->Active(false); // 
    m_Buffs[wftotem->Name()] = *wftotem;
    Buff *hastePotion = new Buff("Haste Potion");
    hastePotion->addAttribute(Attribute("HasteRating", 50)); // haste potion
    hastePotion->Active(false); // 
    m_Buffs[hastePotion->Name()] = *hastePotion;
    Buff *retri = new Buff("Retribution Paladin");
    retri->addAttribute(Attribute("CritRating", 3*CritRating)); // retri Pala
    retri->addAttribute(Attribute("Special", 110001)); // retri Pala
    retri->Active(false); // 
    m_Buffs[retri->Name()] = *retri;
    Buff *ffire = new Buff("Faerie Fire");
    ffire->addAttribute(Attribute("ArmorPenetration",610));
    ffire->Active(true);
    m_Buffs[ffire->Name()] = *ffire;
    Buff *sarmor = new Buff("Sunder Armor");
    sarmor->addAttribute(Attribute("ArmorPenetration",520*5));
    sarmor->Active(true);
    m_Buffs[sarmor->Name()] = *sarmor;
    Buff *reck = new Buff("Curse of Recklessness");
    reck->addAttribute(Attribute("ArmorPenetration",800));
    reck->Active(false),
    m_Buffs[reck->Name()] = *reck;
    Buff *impHunter = new Buff("Improved Hunter's Mark");
    impHunter->addAttribute(Attribute("AttackPower",110));
    impHunter->Active(false),
    m_Buffs[impHunter->Name()] = *impHunter;
    Buff *expWeak = new Buff("Expose Weakness");
    expWeak->addAttribute(Attribute("AttackPower",200));
    expWeak->Active(false),
    m_Buffs[expWeak->Name()] = *expWeak;
    Buff *drums1 = new Buff("1x Drums of Battle");
    drums1->addAttribute(Attribute("HasteRating",20));
    drums1->Active(false),
    m_Buffs[drums1->Name()] = *drums1;
    Buff *drums2 = new Buff("2x Drums of Battle");
    drums2->addAttribute(Attribute("HasteRating",40));
    drums2->Active(false),
    m_Buffs[drums2->Name()] = *drums2;
    Buff *drums3 = new Buff("3x Drums of Battle");
    drums3->addAttribute(Attribute("HasteRating",60));
    drums3->Active(false),
    m_Buffs[drums3->Name()] = *drums3;
    Buff *bfrenzy = new Buff("Blood Frenzy");
    bfrenzy->addAttribute(Attribute("Special",110002));
    bfrenzy->Active(false),
    m_Buffs[bfrenzy->Name()] = *bfrenzy ;
    Buff *demonsl = new Buff("Elixir of Demonslaying");
    demonsl->addAttribute(Attribute("AttackPower",265));
    demonsl->Active(false),
    m_Buffs[demonsl->Name()] = *demonsl ;
}
void Character::initGoodAttributes()
{
    m_GoodAttributes.clear();
    for(int i = 1;i<weo::engine::item::KeyValuesLength;i++)
    {
        m_Equip.Mode(4);
        handleAttribute(Attribute(i,100));
        for(unsigned int k = getAttributesStart();k<m_AttributesVector.size();k++)
        {
            unsigned int value = weo::engine::item::Attribute::getAttributeValue(m_AttributesVector[k]);
            if(m_Equip[value] > 0)
            {
                if(m_GoodAttributes.count(i) == 0)
                {
                    m_GoodAttributes.insert(i);
                }
            }
        }
        m_Equip.ResetTest();
    }
    m_GoodAttributes.insert(weo::engine::item::Attribute::getAttributeValue("Special"));
    m_GoodAttributes.erase(weo::engine::item::Attribute::getAttributeValue("Health"));
}
//{ None = 0, Shaman = 1, Priest = 2, Mage = 4, Warrior = 8, Rogue = 16, Hunter = 32, Paladin = 64, Druid = 128, Warlock = 256 }
void ::InitChar()
{
    ClassMap[classes[0]] = 0;
    for(int i = 1;i<classCount;i++)
    {
        ClassMap[classes[i]] = 1 << (i-1);
    }
}
unsigned int weo::engine::character::Character::isAllowed(const std::string& value)
{
    if(ClassMap.empty())
    {
        InitChar();
    }
    return ClassMap[value];
}
const std::vector<std::string> weo::engine::character::Character::returnAllowed(const int value)
{
    std::vector<std::string> retval;
    for(int i = 1;i<classCount;i++)
    {
        int bit = isAllowed(classes[i]);
        if((value & bit) > 0)
        {
            retval.push_back(classes[i]);
        }
    }
    return retval;
}
bool Character::filterItemCharacter(const weo::engine::item::Item* item)
{
    /*
    if(item->Name() == "Testgem")
    {
        cout << item->Name() << endl;
    }
    */
    if(item->Type() == 5 && (item->Unique() || item->Quality() < 3 || item->Level() < 70)) return true;
    if((item->Allowed() & Classnr()) == 0) return true;
    if(item->Attributes()->empty()) return true;
    if(item->Name().find("Atiesh") != string::npos) return true;
    if(item->Slot() == 4 && item->Type() == 5 && item->Subtype() > 14) return false; // outbreak case
    if(item->Level() < m_FilterBelow || item->Level() > m_FilterAbove) return true;
    if((item->Itemsource() & m_FilterSource) > 0) return true;
    if((item->Profession() & m_FilterProfession) > 0) return true;
    if((item->Quality() & m_FilterQuality) > 0) return true;
    if(s_Blacklist.count(item->Id()) > 0) return true;
    std::vector<std::string>::const_iterator it;
    for(it = item->Areaname()->begin();it!= item->Areaname()->end();it++)
    {
        if(m_FilterArea[*it]) return true;
    }
    bool bad = true;
    bool hasSpecial = false;
    for(unsigned int i = 0;i<item->Attributes()->size();i++)
    {
        if(m_GoodAttributes.count(item->Attributes()->at(i).Type()) > 0)
        {
            if(item->Attributes()->at(i).Type() == weo::engine::item::Attribute::getAttributeValue("Special") && item->Attributes()->size() > 1)
            {
                if(hasSpecial) // two or more special ids are fine too
                {
                    bad = false;
                    break;
                }
                hasSpecial = true;
                continue;
            }
            else
            {
                bad = false;
                break;
            }
        }
    }
    return bad;
}
bool cmpptr(const Item* a, const Item* b)
{
    return a->Name() < b->Name();
}
void Character::filterEquip(std::vector<std::vector<const weo::engine::item::Item*>>& items, const Equipment equip)
{
    filterEquip(items);
    for(int i = 0;i<weo::engine::Slotcount;i++)
    {
        const Item *item = equip.Items[i];
        if(item == NULL) continue;
        std::vector<const weo::engine::item::Item*>::iterator it2 = std::find(items[i].begin(),items[i].end(),item);
        if(it2 == items[i].end())
        {
            items[i].push_back(item);
        }
        for(int k = 0;k<item->Sockets()->Count();k++)
        {
            const Item *gem = equip.Gems[i*3+k];
            if(gem == NULL) continue;
            it2 = std::find(items[weo::engine::GemSlot].begin(),items[weo::engine::GemSlot].end(),gem);
            if(it2 == items[weo::engine::GemSlot].end())
            {
                items[weo::engine::GemSlot].push_back(gem);
            }
        }
    }
    std::vector<std::vector<const weo::engine::item::Item*>>::iterator it;
    for(it = items.begin();it!= items.end();it++)
    {
        std::sort(it->begin(),it->end(),cmpptr);
    }
}
void Character::filterEquip(std::vector<std::vector<const weo::engine::item::Item*>>& items)
{
    std::vector<std::vector<const weo::engine::item::Item*>>::iterator it;
    for(it = items.begin();it!= items.end();it++)
    {
        it->erase(std::remove_if(it->begin(), it->end(), boost::bind1st(boost::mem_fun(&Character::filterItemCharacter),this)),it->end());
        it->push_back(weo::engine::item::Item::None());     
        std::sort(it->begin(),it->end(),cmpptr);
    }
    std::set<unsigned int>::iterator wit;
    for(wit = s_Whitelist.begin();wit != s_Whitelist.end();wit++)
    {
        const Item* item = Itemdatabase::getInstance()->getPtrbyId(*wit);
        if(item->Type() == 1)
        {
            if(item->Slot() < 11)
            {
                items[item->Slot() - 1].push_back(item);
            }
            else
            {
                items[15].push_back(item);
            }
        }		
        else if(item->Type() == 2)
        {
            items[10].push_back(item);
            items[11].push_back(item);
        }
        else if(item->Type() == 3)
        {
            items[12].push_back(item);
            items[13].push_back(item);
        }		
        else if(item->Type() == 4)
        {
            if(item->Slot() == 1)
            {
                items[14].push_back(item);
                items[15].push_back(item);
            }
            else if(item->Slot() == 2 || item->Slot() == 4)
            {
                items[14].push_back(item);
            }
            else if(item->Slot() == 3)
            {
                items[15].push_back(item);
            }
            else if(item->Slot() == 5)
            {
                items[16].push_back(item);
            }
        }
        else if(item->Type() == 5 && item->Slot() == 0)
        {
            items[17].push_back(item);
        }
    }

}
void Character::setConditions(const std::vector<std::pair<unsigned int, float>> value)
{
    // cleaning up old conditions
    std::vector<unsigned int>::const_iterator itconst;
    for(itconst = m_CondCache.begin();itconst != m_CondCache.end(); itconst++)
    {
        std::vector<std::string>::iterator it = std::find(m_AttributesVector.begin(), m_AttributesVector.end(), weo::engine::item::KeyValues[*itconst]);
        if(it != m_AttributesVector.end())
        {
            m_AttributesVector.erase(it);
        }
        m_GoodAttributes.erase(*itconst);
    }
    m_CondCache.clear();
    std::vector<std::pair<unsigned int, float>>::const_iterator it;
    for(it = value.begin(); it != value.end();it++)
    {
        if(m_GoodAttributes.count(it->first) == 0)
        {
            m_CondCache.push_back(it->first);
            m_AttributesVector.push_back(weo::engine::item::KeyValues[it->first]);
            m_GoodAttributes.insert(it->first);
        }
    }
    m_Conditions = value;
}
void Character::handleAttribute(const Attribute& attr)
{
    switch(attr.Type())
    {
    case 1:
        m_Equip[attr.Type()] += (m_HasBok ? 1.1f : 1.0f) * attr.Value();
        handleAttribute(Attribute(30,(m_HasBok ? 1.1f : 1.0f) * attr.Value()*Agi2Ap()));
        handleAttribute(Attribute(6,(m_HasBok ? 1.1f : 1.0f) * attr.Value()*Agi2Crit()*CritRating));
        handleAttribute(Attribute(33,(m_HasBok ? 1.1f : 1.0f) * attr.Value()*2));
        handleAttribute(Attribute(14,(m_HasBok ? 1.1f : 1.0f) * attr.Value()*Agi2Dodge()*DodgeRating));
        break;
    case 2:
        m_Equip[attr.Type()] += (m_HasBok ? 1.1f : 1.0f) * attr.Value();
        handleAttribute(Attribute(35,(m_HasBok ? 1.1f : 1.0f) * attr.Value() * 15));
        handleAttribute(Attribute(12,((m_HasBok ? 1.1f : 1.0f) * attr.Value() * Int2Crit()) * CritSpellRating));
        break;
    case 3:
        m_Equip[attr.Type()] += (m_HasBok ? 1.1f : 1.0f) * attr.Value();
        handleAttribute(Attribute(30,(m_HasBok ? 1.1f : 1.0f) * attr.Value() * Str2Ap()));
        handleAttribute(Attribute(17,(m_HasBok ? 1.1f : 1.0f) * attr.Value() * 0.05f));
        break;
    case 4:
        m_Equip[attr.Type()] += (m_HasBok ? 1.1f : 1.0f) * attr.Value();
        handleAttribute(Attribute(34,(m_HasBok ? 1.1f : 1.0f) * attr.Value() * 10));
        break;
    case 5:
        m_Equip[attr.Type()] += (m_HasBok ? 1.1f : 1.0f) * attr.Value();
        break;
    case 18:
        m_Equip[attr.Type()] += attr.Value();
        break;
    case 23:
        m_Equip[attr.Type()] += attr.Value();
        handleAttribute(Attribute(20,attr.Value()));
        break;
    case 44:
        for(int i = 39;i<44;i++)
        {
            handleAttribute(Attribute(i,attr.Value()));
        }
        break;
    case 45:
        handleAttribute(m_Equip.handleSpecial((unsigned int) attr.Value()));
        break;
    default:
        m_Equip[attr.Type()] += attr.Value();
        break;
    }
}
void Character::evaluteItem(const weo::engine::item::Item& item, const unsigned int slot)
{
    for(attrit = item.Attributes()->begin();attrit != item.Attributes()->end();attrit++)
    {
        handleAttribute(*attrit);
    }
}
bool Character::evaluateEquip(const ItemPtr *items, const GemPtr *gems, const EnchantPtr *enchants )
{
    m_Equip.Mode(2);
    m_Equip.ResetEquip();
    m_Equip.setItems(items);
    m_Equip.setGems(gems);
    m_Equip.setEnchants(enchants);
    std::vector<weo::engine::item::Attribute>::const_iterator attrit;
    std::map<size_t,unsigned int> setItems;
    std::map<size_t,const std::vector<std::pair<unsigned char,weo::engine::item::Attribute>>*> setBonus;
    std::map<size_t,const std::vector<std::pair<unsigned char,weo::engine::item::Attribute>>*>::iterator itsB;
    for(int i = 0;i<weo::engine::Slotcount;i++)
    {
        if(items[i] == NULL) continue;
        const Item *item = items[i];
        if(item->Set()->Hash() > 0)
        {
            setItems[item->Set()->Hash()]++;
            setBonus[item->Set()->Hash()] = item->Set()->Bonus();
        }
        evaluteItem(*item, i);
    }
    for(itsB = setBonus.begin();itsB != setBonus.end();itsB++)
    {
        for(unsigned int i = 0;i<itsB->second->size();i++)
        {
            if(setItems[itsB->first] >= itsB->second->at(i).first)
            {
                handleAttribute(itsB->second->at(i).second);
            }
        }
    }
    int counter = 0;
    for(int i = 0;i<weo::engine::Slotcount;i++)
    {
        const ItemPtr item = items[i];
        if(items == NULL) continue;
        bool match = true;
        int socketcount = item->Sockets()->Count();
        for (int k = 0; k < socketcount; k++)
        {
            const GemPtr gem = gems[counter*3+k];
            if(gem == NULL) continue;
            for(attrit = gem->Attributes()->begin();attrit!=gem->Attributes()->end();attrit++)
            {
                handleAttribute(*attrit);
            }
            if((gem->Subtype() & item->Sockets()->Colors()->at(k)) == 0) match = false;
        }
        if (match)
        {                		
            for(attrit = item->Sockets()->Bonus()->begin();attrit!=item->Sockets()->Bonus()->end();attrit++)
            {
                handleAttribute(*attrit);
            }
        }
        counter++;
    }
    for(int i = 0;i<weo::engine::Slotcount;i++)
    {
        if(enchants[i] == NULL) continue;
        const EnchantPtr enchant = enchants[i];
        for(attrit = enchant->Attributes()->begin();attrit!=enchant->Attributes()->end();attrit++)
        {
            handleAttribute(*attrit);
        }
    }
    m_Equip.Mode(3);
    m_CondFactor = 1.0f;
    std::vector<std::pair<unsigned int, float>>::const_iterator it;
    for(it = m_Conditions.begin(); it != m_Conditions.end();it++)
    {
        if(it->first != weo::engine::item::Attribute::getAttributeValue("Special"))
        {
            if(m_Equip[it->first] < it->second)
            {
                m_CondFactor *= pow(min<float>(m_Equip[it->first]/it->second,1.0f),2.0f);
            }
        }
        else
        {
            if(!m_Equip.hasSpecial(it->second))
            {
                m_CondFactor *= 0.75f;
            }
        }
    }
    if(m_Equip.hasSpecial(110001))
    {
        m_CondFactor *= 1.02f;
    }
    return true;
}
void Character::evaluateBuffs()
{
    m_Equip.Mode(1);
    m_Equip.ResetBuffs();
    std::map<std::string,Buff>::const_iterator it;
    for(it = m_Buffs.begin();it!= m_Buffs.end();it++)
    {
        Buff buff = it->second;
        if(buff.Active())
        {
            for(attrit = buff.getAttributes()->begin();attrit != buff.getAttributes()->end();attrit++)
            {
                handleAttribute(*attrit);
            }
        }
    }
}
const std::vector<const std::pair<std::string,float>> Character::getEquipValues() const
{
    std::vector<const std::pair<std::string,float>> retval;
    for(unsigned int k = getAttributesStart();k<m_AttributesVector.size();k++)
    {
        unsigned int value = weo::engine::item::Attribute::getAttributeValue(m_AttributesVector[k]);
        float attrval = m_Equip.Get(value);
        retval.push_back(std::pair<std::string,float>(m_AttributesVector[k],attrval));
    }
    return retval;
}